﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Network;
using System.Data.Common;
using System.Data;
using Rappelz.GameServer.Network.GameClient;
using Rappelz.GameServer.X2D;
using Rappelz.GameServer.Scripting;


namespace Rappelz.GameServer.Database
{
    public class LocationInfoHeader
    {
        public class Center
        {
            public float x;
            public float y;
            public float z;
        }

        public int nPriority;
        public Center vCenterPositon = new Center();
        public float fRadius;
    }

    /// <summary>
    /// DBLoader_Map
    /// </summary>
    public class DBLoader_Map : IDBProc
    {
        private string m_strString;

        public DBLoader_Map(GameDBManager dbManager)
        {
        }

        BaseObject m_CBObject;

        public void SetCB(BaseObject obj)
        {
            m_CBObject = obj;
        }

        public void RunCB()
        {
            if (m_CBObject != null)
                m_CBObject.onEndQuery();
        }


        public bool onProcess()
        {
            TerrainSeamlessWorldInfo seamlessWorldInfo = new TerrainSeamlessWorldInfo();

            if (!seamlessWorldInfo.Initialize("TerrainSeamlessWorld.cfg", false))
            {
                Globals.Log.Fatal("TerrainSeamlessWorld.cfg read error ! ");
                return false;
            }

            TerrainPropInfo propInfo = new TerrainPropInfo();

            if (!propInfo.Initialize("TerrainPropInfo.cfg"))
            {
                Globals.Log.Fatal("TerrainPropInfo.cfg read error ! ");
                return false;
            }
            GameContent.s_fTileSize = seamlessWorldInfo.m_fTileLength;

            int y = 0;
            float fMapLength = seamlessWorldInfo.m_nSegmentCountPerMap * seamlessWorldInfo.m_fTileLength * seamlessWorldInfo.m_nTileCountPerSegment;
            GameContent.g_fMapLength = fMapLength;
            for (float fAttrLen = seamlessWorldInfo.m_fTileLength * 0.125f;
                  y < seamlessWorldInfo.m_sizMapCount.height;
                  ++y )
            {
                for (int i = 0; i < seamlessWorldInfo.m_sizMapCount.width; ++i )
                {
                    string strLocationFileName = seamlessWorldInfo.GetLocationFileName(i, y);

                    if (strLocationFileName.Length != 0)
                    {
                        int wid = seamlessWorldInfo.GetWorldID(i, y);
                        if (wid != -1 )
                        {
                            SetDefaultLocation(i, y, fMapLength, wid);
                        }
                        LoadLocationFile(ResourceManager.GetFullPathname(strLocationFileName), i, y, fAttrLen, fMapLength);

                        string strScriptFileName = seamlessWorldInfo.GetScriptFileName(i, y);

                        if (strScriptFileName.Length != 0)
                        {
                            Globals.Log.Info("Loading Script: " + strScriptFileName);
                            this.m_strString = ResourceManager.GetFullPathname(strScriptFileName);
                            LoadScriptFile(this.m_strString, i, y, fMapLength, propInfo);

                            string strAttributeFileName = seamlessWorldInfo.GetAttributePolygonFileName(i,y);

                            if (strAttributeFileName.Length != 0 && !GameRule.bSkipLoadingAttribute)
                            {
                                string result = ResourceManager.GetFullPathname(strAttributeFileName);
                                LoadAttributeFile(result, i, y, fAttrLen, fMapLength);
                            }
                        }
                    }
                }
            }

            Globals.Log.Info("Map Loading Complete..");
            return true;
        }

        private void SetDefaultLocation(int x, int y, float fMapLength, int LocationId)
        {
            Pointf begin = new Pointf();
            Pointf end = new Pointf();

            begin.x = (x * fMapLength);
            begin.y = (y * fMapLength);
            end.x = ((x + 1) * fMapLength);
            end.y = ((y + 1) * fMapLength);
            GameContent.MapLocationInfo li = new GameContent.MapLocationInfo(begin,end, LocationId,2147483646);
            GameContent.RegisterMapLocationInfo(li);
        }

        private void LoadLocationFile(string szFileName, int x, int y, float fAttrLen, float fMapLength)
        {
            GameContent.MapLocationInfo location_info;
            int nCharSize;
            LocationInfoHeader lih = new LocationInfoHeader();
            int nPolygonCount;
            int nPointCount;

            if (!System.IO.File.Exists(szFileName))
            {
                Globals.Log.Debug("File Not Found: {0}", szFileName);
                return;
            }

            try
            {
                System.IO.FileStream _FileStream = new System.IO.FileStream(szFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                System.IO.BinaryReader br = new System.IO.BinaryReader(_FileStream);

                int total_entries = br.ReadInt32();
                for(int i = 0; i < total_entries; ++i)
                {
                    lih.nPriority = br.ReadInt32();
                    lih.vCenterPositon.x = br.ReadSingle();
                    lih.vCenterPositon.y = br.ReadSingle();
                    lih.vCenterPositon.z = br.ReadSingle();
                    lih.fRadius = br.ReadSingle();

                    nCharSize = br.ReadInt32();
                    if (nCharSize > 1)
                    {
                        br.ReadBytes(nCharSize);
                    }
                    
                    nCharSize = br.ReadInt32();
                    GameContent.g_currentLocationId = 0;
                    if (nCharSize <= 1)
                        continue;
                    string script = Marshal.ConvertToString(br.ReadBytes(nCharSize));
                    LuaVM.Instance.RunString(script);

                    if (GameContent.g_currentLocationId == 0)
                        continue;

                    nPolygonCount = br.ReadInt32();
                    for(int cp = 0; cp < nPolygonCount; ++cp)
                    {
                        nPointCount = br.ReadInt32();

                        float sx = x * fMapLength;
                        float sy = y * fMapLength;
                        List<Pointf> points = new List<Pointf>();

                        for(int p = 0; p < nPointCount; ++p)
                        {
                            Pointf pt = new Pointf();
                            pt.x = sx + ((float)br.ReadInt32()*fAttrLen);
                            pt.y = sy + ((float)br.ReadInt32() * fAttrLen);
                            points.Add(pt);
                        }
                        location_info = new GameContent.MapLocationInfo(points, GameContent.g_currentLocationId, 0);
                        GameContent.RegisterMapLocationInfo(location_info);
                    }
                }
                _FileStream.Close();
                _FileStream.Dispose();
                _FileStream = null;
                br.Close();
            }
            catch (System.IO.FileNotFoundException)
            {
                Globals.Log.Error("File Not Found: {0}", szFileName);
            }
            catch (System.Exception ex)
            {
                Globals.Log.Error("Error Loading Location File: {0} - {1}", szFileName, ex);
            }
        }

        private void LoadScriptFile(string szFullPathName, int x, int y, float fMapLength, TerrainPropInfo propInfo)
        {
            NfsHeader header = new NfsHeader();

            if (!System.IO.File.Exists(szFullPathName))
            {
                Globals.Log.Debug("File Not Found: {0}", szFullPathName);
                return;
            }


            try
            {
                System.IO.FileStream _FileStream = new System.IO.FileStream(szFullPathName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                System.IO.BinaryReader br = new System.IO.BinaryReader(_FileStream);

                header.szSign = Marshal.ConvertToString(br.ReadBytes(16));
                header.dwVersion = (uint) br.ReadInt32();
                header.dwEventLocationOffset = (uint)br.ReadInt32();
                header.dwEventScriptOffset = (uint)br.ReadInt32();
                header.dwPropScriptOffset = (uint)br.ReadInt32();

                if (header.szSign != "nFlavor Script")
                {
                    Globals.Log.Error("Invalid Script Header! " + szFullPathName);
                    return;
                }
                if (header.dwVersion != 2)
                {
                    Globals.Log.Error("Invalid Script Header! " + szFullPathName);
                    return;
                }

                br.BaseStream.Position = header.dwEventLocationOffset;
                LoadRegionInfo(br, x, y, fMapLength);
                br.BaseStream.Position = header.dwEventScriptOffset;
                LoadRegionScriptInfo(br);
                br.BaseStream.Position = header.dwPropScriptOffset;
                LoadPropScriptInfo(br, propInfo, x, y, fMapLength);
                GameContent.s_nCurrentRegionIdx = GameContent.g_vRegionList.Count;

                _FileStream.Close();
                _FileStream.Dispose();
                _FileStream = null;
                br.Close();
            }
            catch (System.IO.FileNotFoundException)
            {
                Globals.Log.Error("File Not Found: {0}", szFullPathName);
            }
            catch (System.Exception ex)
            {
                Globals.Log.Error("Error Loading Location File: {0} - {1}", szFullPathName, ex);
            }
        }

        private void LoadRegionInfo(System.IO.BinaryReader br, int x, int y, float fMapLength)
        {
            int nLocationCount = br.ReadInt32();

            float sx = x * fMapLength;
            float sy = y * fMapLength;

            for(int i = 0; i < nLocationCount; ++i)
            {
                ScriptRegion sr = new ScriptRegion();
                sr.left = (GameContent.s_fTileSize * (float) br.ReadInt32()) + sx;
                sr.top = (GameContent.s_fTileSize * (float) br.ReadInt32()) + sy;
                sr.right = (GameContent.s_fTileSize * (float) br.ReadInt32()) + sx;
                sr.bottom = (GameContent.s_fTileSize * (float) br.ReadInt32()) + sy;
                int nLength = br.ReadInt32();
                if(nLength > 0)
                    sr.strName = Marshal.ConvertToString(br.ReadBytes(nLength));

                GameContent.g_vRegionList.Add(sr);
            }
        }

        private void LoadRegionScriptInfo(System.IO.BinaryReader br)
        {
            string szBox;
            string szRight;
            string szTop;
            string szLeft;
            string szBottom;

            int nScriptCount = br.ReadInt32();
            for (int i = 0; i < nScriptCount; ++i)
            {
                ScriptRegionInfo ri = new ScriptRegionInfo();
                ri.nRegionIndex = br.ReadInt32();
                ri.nRegionIndex += GameContent.s_nCurrentRegionIdx;
                ScriptRegion sr = GameContent.g_vRegionList[ri.nRegionIndex];
                szRight = GameContent.g_vRegionList[ri.nRegionIndex].right.ToString();
                szTop = GameContent.g_vRegionList[ri.nRegionIndex].top.ToString();
                szLeft = GameContent.g_vRegionList[ri.nRegionIndex].left.ToString();
                szBottom = GameContent.g_vRegionList[ri.nRegionIndex].bottom.ToString();
                szBox = String.Format("{0},{1},{2},{3}",szLeft,szTop,szRight,szBottom);
                int nFunctionCount = br.ReadInt32();
                for (int x = 0; x < nFunctionCount; ++x)
                {
                    ScriptTag nt = new ScriptTag();
                    nt.nTrigger = br.ReadInt32();
                    int cc = br.ReadInt32();
                    if(cc > 0)
                    {
                        nt.strFunction = Marshal.ConvertToString(br.ReadBytes(cc));
                        nt.strFunction = nt.strFunction.Replace("#LEFT", szLeft);
                        nt.strFunction = nt.strFunction.Replace("#TOP", szTop);
                        nt.strFunction = nt.strFunction.Replace("#RIGHT", szRight);
                        nt.strFunction = nt.strFunction.Replace("#BOTTOM", szBottom);
                        nt.strFunction = nt.strFunction.Replace("#BOX", szBox);
                        nt.strFunction = nt.strFunction.Replace("#box", szBox);
                    }
                    ri.vInfoList.Add(nt);
                }

                GameContent.g_vScriptEvent.Add(ri);

            }
        }

        private void LoadPropScriptInfo(System.IO.BinaryReader br, TerrainPropInfo terrainPropInfo, int x, int y, float fMapLength)
        {
            List<PropContactScriptInfo.FunctionList> vFunctionList = new List<PropContactScriptInfo.FunctionList>();

            int nScriptCount = br.ReadInt32();

            float rx = x * fMapLength;
            float ry = y * fMapLength;

            for(int i = 0; i < nScriptCount; ++i)
            {
                PropContactScriptInfo tag = new PropContactScriptInfo();
                tag.prop_id = br.ReadInt32();
                tag.x = br.ReadSingle() + rx;
                tag.y = br.ReadSingle() + ry;
                int model_id = br.ReadInt16();

                TerrainPropInfo.PropType tpt = terrainPropInfo.m_pPropInfo[model_id].Type;
                if (tpt == TerrainPropInfo.PropType.NPC)
                {
                    tag.prop_type = 0;
                }
                else
                {
                    if (tpt == TerrainPropInfo.PropType.UseNX3)
                        tag.prop_type = 1;
                }
                int nFunctionCount = br.ReadInt32();

                vFunctionList = new List<PropContactScriptInfo.FunctionList>();
                for (int t = 0; t < nFunctionCount; ++t)
                {
                    PropContactScriptInfo.FunctionList nt = new PropContactScriptInfo.FunctionList();
                    nt.trigger_id = br.ReadInt32();
                    int cc = br.ReadInt32();
                    if(cc > 0)
                    {
                        nt.stdFunction = Marshal.ConvertToString(br.ReadBytes(cc));
                    }
                    vFunctionList.Add(nt);
                }
                GameContent.RegisterPropContactScriptInfo(tag.prop_id,tag.prop_type,model_id,tag.x,tag.y,vFunctionList);
            }
        }

        public void LoadAttributeFile(string szFileName, int x, int y, float fAttrLen, float fMapLength)
        {
            if (!System.IO.File.Exists(szFileName))
            {
                Globals.Log.Debug("File Not Found: {0}", szFileName);
                return;
            }


            try
            {
                System.IO.FileStream _FileStream = new System.IO.FileStream(szFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                System.IO.BinaryReader br = new System.IO.BinaryReader(_FileStream);

                int total_entries = br.ReadInt32();
                for(int i = 0; i < total_entries; ++i)
                {
                    int nPointCount = br.ReadInt32();

                    float sx = x * fMapLength;
                    float sy = y * fMapLength;
                    List<Pointf> points = new List<Pointf>();

                    for(int p = 0; p < nPointCount; ++p)
                    {
                        Pointf pt = new Pointf();
                        pt.x = sx + ((float)br.ReadInt32() * fAttrLen);
                        pt.y = sy + ((float)br.ReadInt32() * fAttrLen);
                        points.Add(pt);
                    }
                    PolygonF pg = new PolygonF(points);
                    GameContent.RegisterBlockInfo(pg);
                    if (nPointCount < 50 )
                        GameContent.RegisterAutoCheckBlockInfo(pg);

                }
                _FileStream.Close();
                _FileStream.Dispose();
                _FileStream = null;
                br.Close();
            }
            catch (System.IO.FileNotFoundException)
            {
                Globals.Log.Error("File Not Found: {0}", szFileName);
            }
            catch (System.Exception ex)
            {
                Globals.Log.Error("Error Loading Attribute File: {0} - {1}", szFileName, ex);
            }

        }


        public bool InitMapInfo()
        {
            foreach (ScriptRegionInfo ri in GameContent.g_vScriptEvent)
            {
                foreach (ScriptTag tag in ri.vInfoList)
                {
                    if (tag.nTrigger == 0)
                    {
                        Globals.Log.Debug(tag.strFunction);
                        LuaVM.Instance.RunString(tag.strFunction);
                    }
                }
            }
            return true;
        }
    }




}
